/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.vcs.cmdline.list;
import org.netbeans.modules.vcs.cmdline.VcsListCommand;
import org.netbeans.modules.vcs.cmdline.Variables;
import org.netbeans.modules.vcs.util.*;
import org.netbeans.modules.vcs.cmdline.exec.*;
import java.io.*;
import java.util.*;
import java.beans.*;
import java.text.*;
/**
* List command for CVS.
* @author Martin Entlicher
* @version
*/
public class CvsListCommand extends VcsListCommand implements RegexListener {
private Debug E=new Debug("CvsListCommand",true); // NOI18N
private Debug D=E;
private String rootDir=null;
private String dir=null;
private String cmd=null;
private String cvsRoot=null;
private boolean shouldFail=false;
private Vector files=new Vector(30);
private StringBuffer dataBuffer=new StringBuffer(4096);
//private StringBuffer errorBuffer = new StringBuffer(256);
private NoRegexListener stdoutNRListener = null;
private NoRegexListener stderrNRListener = null;
private RegexListener stderrListener = null;
private String dataRegex = null;
private String errorRegex = null;
private String input = null;
private long timeout = 0;
private static final String CVS_DIRNAME = "CVS";
private static final String[] CVS_DIRCONTENT = {"Entries", "Repository", "Root"};
/** Creates new CvsListCommand */
public CvsListCommand() {
}
private void initVars(Hashtable vars, String[] args) {
this.cmd = MiscStuff.array2string(args);
this.rootDir = (String) vars.get("ROOTDIR"); // NOI18N
if (this.rootDir == null) {
this.rootDir = "."; // NOI18N
//vars.put("ROOTDIR","."); // NOI18N
}
this.dir = (String) vars.get("DIR"); // NOI18N
if (this.dir == null) {
this.dir = ""; // NOI18N
//vars.put("DIR","."); // NOI18N
}
String module = (String) vars.get("MODULE"); // NOI18N
D.deb("rootDir = "+rootDir+", module = "+module+", dir = "+dir); // NOI18N
if (dir.equals("")) { // NOI18N
dir=rootDir;
if (module != null && module.length() > 0) dir += File.separator + module;
} else {
if (module == null)
dir=rootDir+File.separator+dir;
else
dir=rootDir+File.separator+module+File.separator+dir;
}
if (dir.charAt(dir.length() - 1) == File.separatorChar)
dir = dir.substring(0, dir.length() - 1);
D.deb("dir="+dir); // NOI18N
String dataRegex = (String) vars.get("DATAREGEX"); // NOI18N
if (dataRegex != null) this.dataRegex = dataRegex;
String errorRegex = (String) vars.get("ERRORREGEX"); // NOI18N
if (errorRegex != null) this.errorRegex = errorRegex;
D.deb("dataRegex = "+dataRegex+", errorRegex = "+errorRegex); // NOI18N
this.input = (String) vars.get("INPUT"); // NOI18N
if (this.input == null) this.input = "Cancel/n"; // NOI18N
this.timeout = ((Long) vars.get("TIMEOUT")).longValue(); // NOI18N
}
private boolean isCVSDir() {
File d=new File(dir);
String[] files=d.list();
if (files != null) {
for(int i = 0; i < files.length; i++)
if (files[i].equals("CVS")) return true; // NOI18N
}
shouldFail=true ;
return false;
}
//-----------------------------------
private void runStatusCommand(Hashtable vars){
/*
vars.put("DIR",dir);
vars.put("CVSROOT",cvsRoot);
*/
Variables v=new Variables();
String prepared=v.expand(vars,cmd, true);
D.deb("prepared = "+prepared); // NOI18N
D.deb("DIR = '"+(String) vars.get("DIR")+"'"+", dir = '"+this.dir+"'"); // NOI18N
ExternalCommand ec=new ExternalCommand(prepared);
if (stderrListener != null) {
String[] command = { "LIST: "+prepared }; // NOI18N
stderrListener.match(command);
}
if (stderrNRListener != null) stderrNRListener.match("LIST: "+prepared); // NOI18N
ec.setTimeout(timeout);
ec.setInput(input);
try{
D.deb("stdout dataRegex = "+dataRegex); // NOI18N
ec.addStdoutRegexListener(this,dataRegex);
}
catch (BadRegexException e){
//E.err(e,"bad regex"); // NOI18N
//errorBuffer.append("CvsList: Bad data regex "+dataRegex+"\n"); // NOI18N
if (stderrListener != null) {
String[] elements = { "CvsList: Bad data regex "+dataRegex+"\n" }; // NOI18N
stderrListener.match(elements);
}
//System.err.println("CvsList: Bad regex "+dataRegex);
shouldFail=true ;
}
try{
ec.addStderrRegexListener(new RegexListener () {
public void match(String[] elements){
//D.deb("stderr match:"+MiscStuff.arrayToString(elements)); // NOI18N
//errorBuffer.append(elements[0]+"\n"); // NOI18N
//System.err.println("CvsList: stderr: "+elements[0]);
shouldFail=true ;
}
},errorRegex);
if (this.stderrListener != null) ec.addStderrRegexListener(stderrListener, errorRegex);
ec.addStderrRegexListener(this,dataRegex); // Because of "Examining" status // NOI18N
}
catch (BadRegexException e){
//E.err(e,"bad regex"); // NOI18N
//errorBuffer.append("CvsList: Bad error regex "+errorRegex+"\n"); // NOI18N
if (stderrListener != null) {
String[] elements = { "CvsList: Bad error regex "+errorRegex+"\n" }; // NOI18N
stderrListener.match(elements);
}
//System.err.println("CvsList: Bad regex "+errorRegex);
shouldFail=true ;
}
if (this.stdoutNRListener != null) ec.addStdoutNoRegexListener(stdoutNRListener);
if (this.stderrNRListener != null) ec.addStderrNoRegexListener(stderrNRListener);
//D.deb("ec="+ec); // NOI18N
if( ec.exec() != ExternalCommand.SUCCESS ){
//E.err("exec failed "+ec.getExitStatus()); // NOI18N
shouldFail=true;
}
}
//------------------------------------------
private boolean furtherExamining(String data, int index) {
while(Character.isWhitespace(data.charAt(index))) index++;
return (data.charAt(index) == '.');
}
//-------------------------------------------
private void fillHashtable(Hashtable filesByName) {
String data=new String(dataBuffer);
String examiningStr = "status: Examining"; // NOI18N
int pos=0;
int index=0;
/* I expect file listing in the form: File: <filename> Status: <status>
* There has to be info line about examining directories.
* (Regex ^(File:.*Status:.*$)|(cvs status.*))
*/
int fileIndex;
int examIndex = data.indexOf(examiningStr, pos);
if (examIndex < 0) {
examiningStr = "server: Examining"; // NOI18N
examIndex = data.indexOf(examiningStr, pos);
}
boolean examining = true;
if (examIndex < 0) {
E.err("Warning: No examining info from cvs status command !"); // NOI18N
examining = false;
} else {
examining = furtherExamining(data, examIndex += examiningStr.length());
examIndex = data.indexOf(examiningStr, examIndex);
}
fileIndex=data.indexOf("File:",pos); // NOI18N
while( examining && fileIndex >=0 ){
//int fileIndex=data.indexOf("File:",pos); // NOI18N
int statusIndex=data.indexOf("Status:",pos); // NOI18N
int nextIndex=data.indexOf("\n",statusIndex); // NOI18N
if( nextIndex<0 ){
nextIndex=data.length()-1;
}
D.deb("fillHashtable: fileIndex = "+fileIndex+", statusIndex = "+statusIndex); // NOI18N
if( fileIndex>=0 && statusIndex>=0 ){
fileIndex+="File:".length(); // NOI18N
String fileName=data.substring(fileIndex,statusIndex).trim();
int i=-1;
if( (i=fileName.indexOf("no file")) >=0 ){ // NOI18N
fileName=fileName.substring(i+7).trim();
}
//D.deb("fileName="+fileName); // NOI18N
String fileDetails=data.substring(index,nextIndex);
//D.deb("fileDetails="+fileDetails); // NOI18N
int eolIndex=data.indexOf("\n",statusIndex); // NOI18N
String fileStatus="Unknown"; // NOI18N
if( statusIndex>=0 && eolIndex>=0 ){
statusIndex+="Status:".length(); // NOI18N
fileStatus=data.substring(statusIndex,eolIndex).trim();
}
//D.deb("fileStatus="+fileStatus); // NOI18N
D.deb("fillHashTable: "+"fileName="+fileName+", fileStatus="+fileStatus); // NOI18N
String[] fileStatuses = new String[2];
fileStatuses[0] = fileName;
fileStatuses[1] = fileStatus;
filesByName.put(fileName,fileStatuses);
}
pos=nextIndex;
fileIndex=data.indexOf("File:",pos); // NOI18N
if (examIndex > 0 && examIndex < fileIndex) {
examining = furtherExamining(data, examIndex += examiningStr.length());
examIndex = data.indexOf(examiningStr, examIndex);
}
}
}
/**
* Test if the directory was checked out by CVS or not.
* @param dir the directory name to test
* @return <code>true</code> if the directory was created by CVS, <code>false</code> if not.
*/
private boolean isCVSDirectory(File dir) {
File subdir = new File(dir, CVS_DIRNAME);
if (!subdir.isDirectory()) return false;
for(int i = 0; i < CVS_DIRCONTENT.length; i++) {
File cvsFile = new File(subdir, CVS_DIRCONTENT[i]);
if (!cvsFile.isFile()) return false;
}
return true;
}
/**
* Add local directories with no status information.
* @param filesByName the files container
*/
private void addLocalFiles(Hashtable filesByName){
File d=new File(dir);
String[] files=d.list();
if (files != null) {
String[] fileStatuses = new String[2];
fileStatuses[1] = ""; // NOI18N
for(int i=0;i<files.length;i++){
String fileName=files[i];
//D.deb("fileName="+fileName); // NOI18N
File dirfile = new File(d+File.separator+fileName);
if( dirfile.isDirectory() ){
fileName+="/"; // NOI18N
} else continue;
if( fileName.equals(CVS_DIRNAME+"/") ){ // NOI18N
continue;
}
if (!isCVSDirectory(dirfile)) continue;
if( filesByName.get(fileName)==null ){
D.deb("adding "+fileName); // NOI18N
fileStatuses[0] = fileName;
filesByName.put(fileName, fileStatuses.clone());
}
}
}
}
//--------------------------------------------
/**
* List files of CVS Repository.
* @param vars Variables used by the command
* @param args Command-line arguments
* filesByName listing of files with statuses
* @param stdoutNRListener listener of the standard output of the command
* @param stderrNRListener listener of the error output of the command
* @param stdoutListener listener of the standard output of the command which
* satisfies regex <CODE>dataRegex</CODE>
* @param dataRegex the regular expression for parsing the standard output
* @param stderrListener listener of the error output of the command which
* satisfies regex <CODE>errorRegex</CODE>
* @param errorRegex the regular expression for parsing the error output
*/
public boolean list(Hashtable vars, String[] args, Hashtable filesByName,
NoRegexListener stdoutNRListener, NoRegexListener stderrNRListener,
RegexListener stdoutListener, String dataRegex,
RegexListener stderrListener, String errorRegex) {
this.stdoutNRListener = stdoutNRListener;
this.stderrNRListener = stderrNRListener;
this.stderrListener = stderrListener;
this.dataRegex = dataRegex;
this.errorRegex = errorRegex;
initVars(vars, args);
/*if (isCVSDir())*/ runStatusCommand(vars);
if (!shouldFail) fillHashtable(filesByName);
addLocalFiles(filesByName);
if (shouldFail) {
//errorBuffer.append(allOutputBuffer.toString());
//filesByName.put("ERROR", errorBuffer.toString()); // NOI18N
}
return !shouldFail;
}
public void match(String[] elements) {
dataBuffer.append(elements[0]+"\n"); // NOI18N
D.deb("match: append line '"+elements[0]+"'"); // NOI18N
}
}
/*
* Log
* 26 Gandalf-post-FCS1.24.1.0 3/23/00 Martin Entlicher
* 25 Gandalf 1.24 3/9/00 Martin Entlicher List only directories
* which are in CVS repository.
* 24 Gandalf 1.23 2/10/00 Martin Entlicher Local directories added
* with no status information.
* 23 Gandalf 1.22 1/18/00 Martin Entlicher
* 22 Gandalf 1.21 1/17/00 Martin Entlicher NOI18N + parsing
* examining info corrected
* 21 Gandalf 1.20 1/15/00 Ian Formanek NOI18N
* 20 Gandalf 1.19 1/6/00 Martin Entlicher
* 19 Gandalf 1.18 12/28/99 Martin Entlicher
* 18 Gandalf 1.17 12/14/99 Martin Entlicher Listeners added
* 17 Gandalf 1.16 12/8/99 Martin Entlicher
* 16 Gandalf 1.15 12/2/99 Martin Entlicher
* 15 Gandalf 1.14 12/1/99 Martin Entlicher
* 14 Gandalf 1.13 11/30/99 Martin Entlicher
* 13 Gandalf 1.12 11/10/99 Martin Entlicher
* 12 Gandalf 1.11 11/9/99 Martin Entlicher
* 11 Gandalf 1.10 11/4/99 Martin Entlicher
* 10 Gandalf 1.9 10/26/99 Martin Entlicher
* 9 Gandalf 1.8 10/26/99 Martin Entlicher
* 8 Gandalf 1.7 10/26/99 Martin Entlicher
* 7 Gandalf 1.6 10/26/99 Martin Entlicher
* 6 Gandalf 1.5 10/25/99 Pavel Buzek
* 5 Gandalf 1.4 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 4 Gandalf 1.3 10/13/99 Martin Entlicher
* 3 Gandalf 1.2 10/10/99 Pavel Buzek
* 2 Gandalf 1.1 10/9/99 Martin Entlicher
* 1 Gandalf 1.0 10/7/99 Martin Entlicher initial revision
* $
*/